package com.cygsunri.charge.task;

import com.cygsunri.common.constant.DataName;
import com.cygsunri.common.constant.DeviceType;
import com.cygsunri.common.service.CommonDataService;
import com.cygsunri.measurement.calculate.AbstractComplexEndureCalculateService;
import com.cygsunri.measurement.entity.MeasurementValue;
import com.cygsunri.scada.base.BasePSR;
import com.cygsunri.scada.service.ScadaMeasurementService;
import com.cygsunri.scada.service.ScadaPSRService;
import com.cygsunri.util.DateUtil;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 光伏子站计算量
 */
@Component
@Slf4j
@ConditionalOnProperty(prefix = "task.charge", name = "sub", havingValue = "true")
@PropertySource(name = "application.yml", value = {"classpath:application.yml"}, ignoreResourceNotFound = false, encoding = "UTF-8")
public class ChargeSubCalcTask extends AbstractComplexEndureCalculateService {

    @Autowired
    private ScadaPSRService scadaPSRService;

    @Autowired
    private ScadaMeasurementService scadaMeasurementService;

    @Autowired
    private CommonDataService commonDataService;

    private Map<BasePSR, List<BasePSR>> map = new HashMap<>();

    @Bean
    public void chargeSubCalcInit() {
        List<BasePSR> subs = scadaPSRService.getDevicesByType(DeviceType.CHARGE_SUB.getKey());
        for (BasePSR sub : subs) {
            List<BasePSR> charges = Lists.newArrayList();
            List<BasePSR> acCharges = scadaPSRService.getDeviceOfSubstationByType(sub.getId(), DeviceType.AC_CHARGING.getKey());
            charges.addAll(acCharges);
            List<BasePSR> dcCharges = scadaPSRService.getDeviceOfSubstationByType(sub.getId(), DeviceType.DC_CHARGING.getKey());
            charges.addAll(dcCharges);
            map.put(sub, charges);
        }
    }

    @Scheduled(cron = "${task.charge.cron}")
    private void chargeSubCalc() {
        long a = System.currentTimeMillis();
        map.forEach((sub, charges) -> {
            calcPower(sub, charges);
            calcTotalCharge(sub, charges);
            calcyearCharge(sub, charges);
            calcmonthCharge(sub, charges);
            calcDayCharge(sub, charges);
            calcUtilization(sub, charges);
            chargeStatus(sub, charges);
        });

        log.info("充电桩计算量耗时{}ms", System.currentTimeMillis() - a);
    }

    /**
     * 充电桩合计用电量（通过充电枪计算）
     */
    private void calcTotalCharge(BasePSR sub, List<BasePSR> charges) {
        if (!this.getNeedEndureCalculate(sub.getId(), sub.getName(), DataName.TOTAL_CHARGE)) {
            return;
        }

        ImmutablePair<String, Integer> pair = scadaMeasurementService.getMeasurementID(sub.getId(), DataName.TOTAL_CHARGE);
        if (pair == null) {
            log.warn("找不到id为{}的设备{}在scada中的{}点！", sub.getId(), sub.getName(), DataName.TOTAL_CHARGE);
            return;
        }

        Double v = 0d;
        Integer num = 0;
        for (BasePSR charge : charges) {
            MeasurementValue gun1 = commonDataService.getValue(charge.getId(), DataName.GUN1_TOTAL_CHARGE);
            if (!gun1.isInValid()) {
                v += gun1.getData();
                num++;
            }

            MeasurementValue gun2 = commonDataService.getValue(charge.getId(), DataName.GUN2_TOTAL_CHARGE);
            if (!gun2.isInValid()) {
                v += gun2.getData();
                num++;
            }
        }

        if (num > 0) {
            this.saveMean(pair.getLeft(), v, DateUtil.nowMilliSeconds(), MeasurementValue.Quality.Calc.getKey());
        }
    }

    /**
     * 充电桩年用电量（通过充电枪计算）
     */
    private void calcyearCharge(BasePSR sub, List<BasePSR> charges) {
        if (!this.getNeedEndureCalculate(sub.getId(), sub.getName(), DataName.YEAR_CHARGE)) {
            return;
        }

        ImmutablePair<String, Integer> pair = scadaMeasurementService.getMeasurementID(sub.getId(), DataName.YEAR_CHARGE);
        if (pair == null) {
            log.warn("找不到id为{}的设备{}在scada中的{}点！", sub.getId(), sub.getName(), DataName.YEAR_CHARGE);
            return;
        }
        Double value = 0d;
        int num = 0;
        for (BasePSR charge : charges) {
            MeasurementValue gun1 = commonDataService.getValue(charge.getId(), DataName.GUN1_TOTAL_CHARGE, DateUtil.nowMilliSeconds(), 503);
            if (!gun1.isInValid()) {
                value += gun1.getData();
                num++;
            }

            MeasurementValue gun2 = commonDataService.getValue(charge.getId(), DataName.GUN2_TOTAL_CHARGE, DateUtil.nowMilliSeconds(), 503);
            if (!gun2.isInValid()) {
                value += gun2.getData();
                num++;
            }
        }
        if (num > 0) {
            this.saveMean(pair.getLeft(), value, DateUtil.nowMilliSeconds(), MeasurementValue.Quality.Calc.getKey());
        }
    }

    /**
     * 充电桩月用电量（通过充电枪计算）
     */
    private void calcmonthCharge(BasePSR sub, List<BasePSR> charges) {
        if (!this.getNeedEndureCalculate(sub.getId(), sub.getName(), DataName.MONTH_CHARGE)) {
            return;
        }

        ImmutablePair<String, Integer> pair = scadaMeasurementService.getMeasurementID(sub.getId(), DataName.MONTH_CHARGE);
        if (pair == null) {
            log.warn("找不到id为{}的设备{}在scada中的{}点！", sub.getId(), sub.getName(), DataName.MONTH_CHARGE);
            return;
        }
        Double value = 0d;
        int num = 0;
        for (BasePSR charge : charges) {
            MeasurementValue gun1 = commonDataService.getValue(charge.getId(), DataName.GUN1_TOTAL_CHARGE, DateUtil.nowMilliSeconds(), 502);
            if (!gun1.isInValid()) {
                value += gun1.getData();
                num++;
            }

            MeasurementValue gun2 = commonDataService.getValue(charge.getId(), DataName.GUN2_TOTAL_CHARGE, DateUtil.nowMilliSeconds(), 502);
            if (!gun2.isInValid()) {
                value += gun2.getData();
                num++;
            }
        }
        if (num > 0) {
            this.saveMean(pair.getLeft(), value, DateUtil.nowMilliSeconds(), MeasurementValue.Quality.Calc.getKey());
        }
    }

    /**
     * 充电桩日用电量（通过充电枪计算）
     */
    private void calcDayCharge(BasePSR sub, List<BasePSR> charges) {
        if (!this.getNeedEndureCalculate(sub.getId(), sub.getName(), DataName.DAY_CHARGE)) {
            return;
        }

        ImmutablePair<String, Integer> pair = scadaMeasurementService.getMeasurementID(sub.getId(), DataName.DAY_CHARGE);
        if (pair == null) {
            log.warn("找不到id为{}的设备{}在scada中的{}点！", sub.getId(), sub.getName(), DataName.DAY_CHARGE);
            return;
        }

//        MeasurementValue m = commonDataService.getValue(sub.getId(), DataName.TOTAL_CHARGE, DateUtil.nowMilliSeconds(), 500);
//        if (!m.isInValid()) {
//            this.saveMean(pair.getLeft(), m.getData(), DateUtil.nowMilliSeconds(), MeasurementValue.Quality.Calc.getKey());
//            return;
//        }

        Double value = 0d;
        int num = 0;
        for (BasePSR charge : charges) {
            MeasurementValue gun1 = commonDataService.getValue(charge.getId(), DataName.GUN1_TOTAL_CHARGE, DateUtil.nowMilliSeconds(), 500);
            if (!gun1.isInValid()) {
                value += gun1.getData();
                num++;
            }

            MeasurementValue gun2 = commonDataService.getValue(charge.getId(), DataName.GUN2_TOTAL_CHARGE, DateUtil.nowMilliSeconds(), 500);
            if (!gun2.isInValid()) {
                value += gun2.getData();
                num++;
            }
        }
        if (num > 0) {
            this.saveMean(pair.getLeft(), value, DateUtil.nowMilliSeconds(), MeasurementValue.Quality.Calc.getKey());
        }
    }

    /**
     * 充电桩使用率（通过充电枪计算）
     */
    private void calcUtilization(BasePSR sub, List<BasePSR> charges) {
        if (!this.getNeedEndureCalculate(sub.getId(), sub.getName(), DataName.UTILIZATION)) {
            return;
        }

        ImmutablePair<String, Integer> pair = scadaMeasurementService.getMeasurementID(sub.getId(), DataName.UTILIZATION);
        if (pair == null) {
            log.warn("找不到id为{}的设备{}在scada中的{}点！", sub.getId(), sub.getName(), DataName.UTILIZATION);
            return;
        }

        Double utilization;
        Double use = 0d;
        Double num = 0d;
        for (BasePSR charge : charges) {
            MeasurementValue gun1 = commonDataService.getValue(charge.getId(), DataName.GUN1_STATUS);
            if (!gun1.isInValid()) {
                num++;
                if (gun1.getData() == 1 || gun1.getData() == 2) {
                    use++;
                }
            }

            MeasurementValue gun2 = commonDataService.getValue(charge.getId(), DataName.GUN2_STATUS);
            if (!gun2.isInValid()) {
                num++;
                if (gun2.getData() == 1 || gun2.getData() == 2) {
                    use++;
                }
            }
        }

        if (num > 0) {
            utilization = use / num;
            this.saveMean(pair.getLeft(), utilization * 100, DateUtil.nowMilliSeconds(), MeasurementValue.Quality.Calc.getKey());
        }
    }

    /**
     * 充电桩设备通讯状态
     */
    private void chargeStatus(BasePSR sub, List<BasePSR> charges) {
        for (BasePSR basePSR : charges) {
            MeasurementValue communicationFault = commonDataService.getValue(basePSR.getId(), DataName.COMMUNICATION_FAULT);
            if (!communicationFault.isInValid() && communicationFault.getData() == 1) {
                setDeviceStatus(basePSR, "COMMUNICATION_FAULT");
            } else {
                setDeviceStatus(basePSR, "RUNNING");
            }
        }
    }

    /**
     * 充电桩功率计算
     */
    private void calcPower(BasePSR sub, List<BasePSR> charges) {
        if (!this.getNeedEndureCalculate(sub.getId(), sub.getName(), DataName.TOTAL_ACTIVE_POWER)) {
            return;
        }

        ImmutablePair<String, Integer> pair = scadaMeasurementService.getMeasurementID(sub.getId(), DataName.TOTAL_ACTIVE_POWER);
        if (pair == null) {
            log.warn("找不到id为{}的设备{}在scada中的{}点！", sub.getId(), sub.getName(), DataName.TOTAL_ACTIVE_POWER);
            return;
        }

        Double value = 0d;
        Integer num = 0;
        for (BasePSR charge : charges) {
            MeasurementValue outPower1 = commonDataService.getValue(charge.getId(), DataName.GUN1_OUT_POWER);
            if (!outPower1.isInValid() && outPower1.getData() >= 0) {
                value += outPower1.getData();
                num++;
            }

            MeasurementValue outPower2 = commonDataService.getValue(charge.getId(), DataName.GUN2_OUT_POWER);
            if (!outPower2.isInValid() && outPower2.getData() >= 0) {
                value += outPower2.getData();
                num++;
            }
        }

        if (num > 0) {
            this.saveMean(pair.getLeft(), value, DateUtil.nowMilliSeconds(), MeasurementValue.Quality.Calc.getKey());
        }
    }

}
